// 基于栈的
// 内存解密, 在内存中，释放了，code消失
// arm指令格式：<opcode> {<cond>} {S} <Rd> , <Rn> { , <shift_op2> } 
// <>内的项是必须的，{}内的项是可选的 
// opcode：指令助记符；cond：执行条件；S：是否影响CPSR寄存器的值；Rd：目标寄存器；
// Rn：第1个操作数的寄存器；operand2：第2个操作数； 
// 大多数时候可以根据CPSR的条件标志位觉得是否该执行指令。当条件满足时才执行，否则不执
// S：可选后缀，加上"S"，在指令执行完毕后自动更新CPSR中的条件码标志位的值
// Rd：ARM指令中的目标操作数总是一个寄存器，通常用Rd表示
// Rn：存放第1操作数寄存器
// opcode2：第2操作数，不仅可以是寄存器，还能是立即数，而且能够使用经过位移运算的寄存器和立即数

// 应该对应四个入口 pc = ((_R9 - 4) >> 2) << 5, 下面对应4个_R9, 将要执行指令 glvm_vcode_list[pc];
// 但经我调试发现它们对应同一个入口 sub_9DF6C
// 后面发现有0x1988最终入口sub_9E208
// 指令类型 (_R9 & 0x1F) = [0-20] 加一种默认情况default,_R9代表一条指令，占四个字节
struct lvm_vcode { // 解释型或自定义的code，目前实现了21个虚拟指令
	// 由两大类组成，一类是直接编译进去的默认的，一种是lvm_method实现的
	// vm先拿到vcode, 然后更新runtime->vcode_pc, 接着进入vcode-> handler
	void* handler; // 指令对应的解析方法，其余变量用于解析指令
	int v2; // 暂时都为0
	// 暂时这样命名
	int cond; // 某值(_R9 >> 5) & 0xF 、 (_R9 >> 6) & 0xF、 (_R9 >> 5) & 0x1F
	// (_R9 >> 9) & 0x1F 很多情况略，用于栈计算(保存栈起始地址 + retv_addv*8)用于保存pc_addv
	int op1; // 用于计算当前栈保存原操作1的位置
	int op2; // 用于计算当前栈保存原操作2，的位置(_R9 >> 14) & 0x1F 很多情况略
	int dst; // 用于计算当前栈保存目的操作数的位置，(_R9 >> 19) & 0x1F 很多情况略
	// 一个加值,多种用途 栈计算，vmethod id查找 vcode查找, 返回结果地址计算
	// 取vmthod时pc_addv - 0x17FFFE， 但需小于0x17FFFD
	int addv; // 复合累计值, 类似于arm指令中的shift_op
	int opn; // 可能相当于arm的opcode2
};